﻿/* FocusMeasure.h
 * 
 * Copyright (C) 2020, 2021 Yuan LI
 * email:18069211@qq.com
 * https://blog.csdn.net/liyuanbhu
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or (at
 * your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */


#ifndef FOCUSMEASURE_H
#define FOCUSMEASURE_H
#include <QImage>

double roberts(const QImage &grayImage);
double sobel(const QImage &grayImage);
double laplace(const QImage &grayImage);
double fastRoberts(const QImage &grayImage);
double fastSobel(const QImage &grayImage);
double fastLaplace(const QImage &grayImage);
double discreteVariance(const QImage &grayImage);

class FocusMeasure
{
public:
    enum MeasureMethod{ROBERTS, FAST_ROBERTS, SOBEL, FAST_SOBEL, LAPLACE, FAST_LAPLACE, DISCRETE_VARIANCE};

    FocusMeasure();
    ~FocusMeasure();

    /**
     * @brief score 对一幅图像的清晰程度打分
     * @param image 可以是彩色图像或黑白图像
     * @return 打分值，分越高越清晰。
     */
    double score(const QImage &image) const;

    /**
     * @brief scoreAndRecord 对当前图像的清晰程度打分，如果当前图像比之前的图像清晰，则记录。
     * @param image
     * @param better *better = true 表示当前图像比之前的图像清晰。
     * @return 打分值，分越高越清晰。
     */
    double scoreAndRecord(const QImage &image, bool *better = nullptr);

    /**
     * @brief bestImage 获取最清晰的图像
     * @return
     */
    QImage bestImage() const {return m_bestImage;}

    /**
     * @brief reset 将内部计分清零，最佳图像也清空
     */
    void reset();

    /**
     * @brief setMeasureMethod 设置采用何种判据评价一副图像的清晰程度，默认是 ROBERTS 算子计算梯度
     * @param method
     */
    void setMeasureMethod(MeasureMethod method = ROBERTS);

    /**
     * @brief setZoomFactor 设置 preprocess 时图像的缩放系数。缩小图像以加快计算速度。
     * @param factor 0 和 1 表示不缩放，n 表示缩放为 1/n 大小
     */
    void setZoomFactor(int factor) {m_zoomFactor = factor;}

    /**
     * @brief setRoi 设置刚兴趣区域。计算清晰度时只计算 ROI 区域内的部分。通过设置较小的 ROI 可以加快计算速度
     * @param roi
     */
    void setRoi(QRect roi) { m_roi = roi; }

    /**
     * @brief preprocess 对原始图像进行预处理。将彩色图像变成灰度图像，缩小图像尺寸等操作。
     * @param image 原始的图像
     * @return 输出图像为灰度图像，openCV 格式。以便进一步计算。
     */
    QImage preprocess(const QImage &image) const;

    /**
     * @brief measure 评价一副图像的清晰程度，输入只能为灰度图像。 通常应该使用 score 函数，而不是这个函数
     * @param grayImage
     * @return 输出结果越大表明图像约清晰
     */
    double measure(const QImage &grayImage) const {return m_measureFunc(grayImage);}

private:
    double (*m_measureFunc)(const QImage &);
    int m_zoomFactor;
    QRect m_roi;
    QImage m_bestImage;
    double m_bestScore;
};

#endif // FOCUSMEASURE_H
